package com.plug.controller;


import com.plug.common.consts.Code;
import com.plug.common.model.ExceptionResult;
import com.plug.common.model.JsonResult;
import com.plug.common.utils.IpUtils;
import com.plug.controller.util.AbstractController;
import com.plug.controller.util.cache.KeyUtil;
import com.plug.controller.util.cache.MemoryCache;
import com.plug.entity.PlugContrast;
import com.plug.entity.PlugDatasource;
import com.plug.entity.PlugOperationRecord;
import com.plug.entity.PlugRecord;
import com.plug.service.IPlugContrastService;
import com.plug.service.IPlugDatasourceService;
import com.plug.service.IPlugOperationRecordService;
import com.plug.service.IPlugRecordService;
import com.plug.util.StringUtils;
import net.sf.json.JSONObject;
import org.apache.ibatis.annotations.Param;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.concurrent.TimeoutException;

/**
 * 比较
 * Created by admin on 2016/12/20.
 */
@Controller
@RequestMapping("/compare")
public class CompareController extends AbstractController {
    @Autowired
    private IPlugRecordService plugRecordService;

    @Autowired
    private IPlugContrastService plugContrastService;

    @Autowired
    private IPlugDatasourceService plugDatasourceService;

    @Autowired
    private IPlugOperationRecordService plugOperationRecordService;

    Logger logger = LoggerFactory.getLogger(getClass());

    @RequestMapping(value = "/findRecord", method = RequestMethod.POST)
    @ResponseBody
    public Map<String, Object> findRecord(@RequestParam("page")int page,
                                          @RequestParam("rows")int rows){
        Map<String, Object> resultMap = new HashMap<>();
        rows = 25;
        List<PlugOperationRecord> listMap = plugOperationRecordService.findAll((page - 1) * rows, rows);
        int total = plugOperationRecordService.findTotal();
        resultMap.put("total", total);
        resultMap.put("rows", listMap);
        return resultMap;
    }

    @RequestMapping(value = "/getCompareRecord", method = RequestMethod.POST)
    @ResponseBody
    public ResponseEntity<Object> getCompareRecord(@RequestParam("id")String id){
        try {
            PlugOperationRecord plugOperationRecord = plugOperationRecordService.findByID(id);
            PlugContrast plugContrast = plugContrastService.findByID(plugOperationRecord.getCtId());
            List<PlugRecord> recordList = plugRecordService.findByOperationId(id, 0, 25);

            if(recordList == null || recordList.size() == 0)
                throw new Exception("对比结果出现异常，没有任何数据");

            List<Map<String, Object>> recordListMap = new ArrayList<>();
            String[] srcColumn = null;
            String[] tgtColumn = null;
            for (PlugRecord p : recordList) {
                Map<String,Object> map = new HashMap<>();
                String[] srcData = p.getSrcDesc().split(",&,");
                String[] tgtData = p.getTgtDesc().split(",&,");
                tgtColumn = p.getTgtColumn().split(",&,");
                srcColumn = p.getSrcColumn().split(",&,");
                for (int i = 0; i < srcData.length; i++) {
                    map.put(srcColumn[i], srcData[i]);
                    map.put("tgt_"+tgtColumn[i], tgtData[i]);
                }
                map.put("split_column", " ");
                recordListMap.add(map);
            }

            List<String> columnListMap = new ArrayList<>();

            for (int i = 0; i < srcColumn.length; i++) {
                columnListMap.add(srcColumn[i]);
            }
            columnListMap.add("split_column");
            for (int i = 0; i < tgtColumn.length; i++) {
                columnListMap.add("tgt_"+tgtColumn[i]);
            }

            if(columnListMap.size() == 0) {
                throw new Exception("表结构列值不存在");
            }

            int total = plugRecordService.findByOperationIdTotal(id);
            JsonResult jsonResult = new JsonResult();

            jsonResult.setCode(Code.SUCCESS);
            jsonResult.putData("columnListMap", columnListMap);
            jsonResult.putData("total", total);
            jsonResult.putData("recordListMap", recordListMap);

            return new ResponseEntity<Object>(jsonResult, HttpStatus.OK);
        }catch (Exception e){
            return new ResponseEntity<Object>(new ExceptionResult(e), HttpStatus.OK);
        }
    }

    /**
     *
     * @param plugContrast 任务配置对象
     * @param column 对比列名称
     * @param sort 排序方式
     * @param limit 分页大小
     * @param startTime 开始时间
     * @param endTime 结束时间
     * @param columnTime 时间列
     * @param isTime 判断条件方式
     * @param primaryKey 主键开始位
     * @param request
     * @return
     */
    @RequestMapping(value = "/compare", method = RequestMethod.POST)
    @ResponseBody
    public ResponseEntity<Object> Source(PlugContrast plugContrast,
                                      @RequestParam("column")String column,
                                      @RequestParam("sort")String sort,
                                      @RequestParam("limit")Integer limit,
                                      @RequestParam("startTime")String startTime,
                                      @RequestParam("endTime")String endTime,
                                      @RequestParam("columnTime")String columnTime,
                                      @RequestParam("isTime")Boolean isTime,
                                      @RequestParam("primaryKey")Long primaryKey,
                                      HttpServletRequest request){
        try{
            //根据传入条件查询源备份数据集
            Map<String, Map<String, Object>> srcResultMap = null;
            //根据传入条件查询目标数据集
            Map<String, Map<String, Object>> tgtResultMap = null;
            plugContrast = plugContrastService.findDatasourceByName(plugContrast.getSrcDsId(),plugContrast.getTgtDsId(),plugContrast.getSrcTab());
            if(column.indexOf("全部") != -1){
                column = "*";
            } else if(column.indexOf(plugContrast.getPrimaryKey()) == -1) {
                String[] columns = column.split(",");
                StringBuffer sb = new StringBuffer("`" + plugContrast.getPrimaryKey()+ "`,");
                for (int i = 0; i < columns.length; i++) {
                    sb.append("`" + columns[i] + "`,");
                }
                sb.deleteCharAt(sb.length() - 1);
                column =  sb.toString();
            }
            PlugDatasource srcDataSource = plugDatasourceService.findByID(plugContrast.getSrcDsId());//获取源数据源对象
            PlugDatasource tgtDataSource = plugDatasourceService.findByID(plugContrast.getTgtDsId());//获取目标数据源对象
            String uuid = UUID.randomUUID().toString().toUpperCase();
            if(isTime) {
                if(!StringUtils.isNull(startTime) && !StringUtils.isNull(endTime) && !StringUtils.isNull(columnTime)) {
                    MemoryCache mc = MemoryCache.getInstance();
                    Map<String, Object> tableStrutMap = new HashMap<>();
                    if(mc.get(plugContrast.getTgtDsId() + "_" + plugContrast.getTgtTab()) != null
                            && !mc.get(plugContrast.getTgtDsId() + "_" + plugContrast.getTgtTab()).toString().equals("")){
                        JSONObject jo = JSONObject.fromObject(mc.get(plugContrast.getTgtDsId() + "_" + plugContrast.getTgtTab()));
                        tableStrutMap = JSONObject.fromObject(jo);
                    } else {
                        tableStrutMap = plugRecordService.findTableStrut(tgtDataSource, plugContrast.getTgtTab());//查询表时间数据结构
                        mc.set(plugContrast.getTgtDsId() + "_" + plugContrast.getTgtTab(), JSONObject.fromObject(tableStrutMap), 2592000);
                    }
                    Long total = plugRecordService.findHistoryRecordTotal(tgtDataSource,plugContrast.getTgtTab(),0L,columnTime,
                            tableStrutMap.get(columnTime).toString(),startTime,endTime,plugContrast,true);
                    if (total > KeyUtil.compareMaxNumber){
                        throw new Exception("对比记录超过" + KeyUtil.compareMaxNumber + "条，为了保证数据准确性，请使用即时任务对比！");
                    }
                    Long[] indexLong = plugRecordService.getMaxAndMinIndex(tgtDataSource,plugContrast.getTgtTab(),column,sort,columnTime,
                            tableStrutMap.get(columnTime).toString(),startTime,endTime,plugContrast);
                    //根据传入条件查询源备份数据集
                    srcResultMap = plugRecordService.findHistoryRecord(srcDataSource,plugContrast.getSrcTab(),column,indexLong,plugContrast);
                    //根据传入条件查询目标数据集
                    tgtResultMap = plugRecordService.findHistoryRecord(tgtDataSource,plugContrast.getTgtTab(),column,indexLong,plugContrast);
                }
            } else {
                if(primaryKey != -1){
                    Long total = plugRecordService.findHistoryRecordTotal(tgtDataSource,plugContrast.getTgtTab(),primaryKey,null,
                            null,null,null,plugContrast,false);
                    if (total > KeyUtil.compareMaxNumber){
                        throw new Exception("对比记录超过" + KeyUtil.compareMaxNumber + "条，为了保证数据准确性，请使用即时任务对比！");
                    }
                    Long[] indexLong = plugRecordService.getMaxAndMinIndex(tgtDataSource,plugContrast.getTgtTab(),null,null,column,sort,plugContrast);
                    indexLong[0] = primaryKey;
                    //根据传入条件查询源备份数据集
                    srcResultMap = plugRecordService.findHistoryRecord(srcDataSource,plugContrast.getSrcTab(),indexLong,column,sort,plugContrast);
                    //根据传入条件查询目标数据集
                    tgtResultMap = plugRecordService.findHistoryRecord(tgtDataSource,plugContrast.getTgtTab(),indexLong,column,sort,plugContrast);
                } else {
                    Long[] indexLong = plugRecordService.getMaxAndMinIndex(tgtDataSource,plugContrast.getTgtTab(),0,limit,column,sort,plugContrast);
                    //根据传入条件查询源备份数据集
                    srcResultMap = plugRecordService.findHistoryRecord(srcDataSource,plugContrast.getSrcTab(),indexLong,column,sort,plugContrast);
                    //根据传入条件查询目标数据集
                    tgtResultMap = plugRecordService.findHistoryRecord(tgtDataSource,plugContrast.getTgtTab(),indexLong,column,sort,plugContrast);
                }
            }
            List<PlugRecord> plugRecordList = new ArrayList<>();
            for (String key : tgtResultMap.keySet()){
                Map<String, Object> srcMap = srcResultMap.get(key);
                Map<String, Object> tgtMap = tgtResultMap.get(key);
                String srcData = "";//行源数据
                String tgtData = "";//行目标数据
                String srcColumn = "";
                String tgtColumn = "";
                if(srcResultMap.containsKey(key)) {
                    for(String str : tgtMap.keySet()) {
                        srcColumn += str + ",&,";
                        tgtColumn += str + ",&,";
                        srcData += StringUtils.convertString(srcMap.get(str));
                        srcData += ",&,";
                        tgtData += StringUtils.convertString(tgtMap.get(str));
                        tgtData += ",&,";
                    }
                } else {
                    for(String str : tgtMap.keySet()) {
                        srcColumn += str + ",&,";
                        tgtColumn += str + ",&,";
                        srcData += "    ,&,    ";
                        tgtData += StringUtils.convertString(tgtMap.get(str));
                        tgtData += ",&,";
                    }
                }
                if(!srcData.equals(tgtData)){
                    PlugRecord pl = new PlugRecord();
                    pl.setCreatetime(new Date());
                    pl.setSrcDesc(srcData);
                    pl.setTgtDesc(tgtData);
                    pl.setSrcColumn(srcColumn);
                    pl.setTgtColumn(tgtColumn);
                    pl.setCrId(uuid);
                    plugRecordList.add(pl);
                }
            }
            for (String key : srcResultMap.keySet()){
                Map<String, Object> srcMap = srcResultMap.get(key);
                Map<String, Object> tgtMap = tgtResultMap.get(key);
                String srcData = "";//行源数据
                String tgtData = "";//行目标数据
                String srcColumn = "";
                String tgtColumn = "";
                if(!tgtResultMap.containsKey(key)) {
                    for(String str : srcMap.keySet()) {
                        srcColumn += str + ",&,";
                        tgtColumn += str + ",&,";
                        tgtData += "    ,&,    ";
                        srcData += StringUtils.convertString(srcMap.get(str));
                        srcData += ",&,";
                    }
                }
                if(!srcData.equals(tgtData)){
                    PlugRecord pl = new PlugRecord();
                    pl.setCreatetime(new Date());
                    pl.setSrcDesc(srcData);
                    pl.setTgtDesc(tgtData);
                    pl.setSrcColumn(srcColumn);
                    pl.setTgtColumn(tgtColumn);
                    pl.setCrId(uuid);
                    plugRecordList.add(pl);
                }
            }
            PlugOperationRecord plugOperationRecord = new PlugOperationRecord();//操作人员记录表
            plugOperationRecord.setId(uuid);
            plugOperationRecord.setCreatetime(new Date());
            StringBuffer desc = new StringBuffer("手动对比："+srcDataSource.getDsName()+"("+tgtDataSource.getDsName()+")");
            desc.append("->"+plugContrast.getSrcTab()+"("+plugContrast.getTgtTab()+")");
            desc.append("本次对比共有："+plugRecordList.size()+"条数据不一致；");


            if(isTime){
                desc.append("对比条件添加时间筛选列："+columnTime);
            }
            plugOperationRecord.setDescs(desc.toString());
            plugOperationRecord.setCtId(plugContrast.getId());
            plugOperationRecord.setOperationip(IpUtils.getIpAddress(request));
            plugOperationRecord.setUserId(1L);
            if(plugRecordList.size() > 0) {
                plugRecordService.saveRecordAndOperation(plugRecordList, plugOperationRecord);
            }
            List<String> columnList = plugRecordService.findHistoryColumn(srcDataSource,plugContrast.getSrcTab(),column);
            plugRecordList = new ArrayList<>();
            plugRecordList = plugRecordService.findByOperationId(uuid, 0, 100);
            List<Map<String, Object>> dataList = this.convertList(plugRecordList);


            JsonResult jsonResult = new JsonResult();//源数据集
            jsonResult.setCode(Code.SUCCESS);
            jsonResult.putData("resultList", dataList);
            jsonResult.putData("total", plugRecordService.findByOperationIdTotal(uuid));
            jsonResult.putData("uuid", uuid);
            jsonResult.putData("columnList", columnList);//源数据列集合

            return new ResponseEntity<Object>(jsonResult, HttpStatus.OK);
        } catch (Exception e){
            return new ResponseEntity<Object>(new ExceptionResult(e), HttpStatus.OK);
        }
    }

    //根据源获得表
    @RequestMapping(value = "/getSourceTable", method = RequestMethod.POST)
    @ResponseBody
    public Map<String, Object> getSourceTable(Long id){
        Map<String, Object> resultMap = new HashMap<>();
        List<PlugContrast> plugContrastList = plugContrastService.findAllTable(id);
        List<Map<String, Object>> sourceTableList = new ArrayList<>();
        for (PlugContrast p : plugContrastList){
            Map<String, Object> map  = new HashMap<>();
            map.put("text", p.getSrcTab());
            map.put("value", p.getId());
            sourceTableList.add(map);
        }
        resultMap.put("data", sourceTableList);
        return resultMap;
    }

    @RequestMapping(value = "/loadPages", method = RequestMethod.POST)
    @ResponseBody
    public Map<String,Object> loadPages(@RequestParam("uuid")String uuid,
                                        @RequestParam("page")Integer page,
                                        @RequestParam("limit")Integer limit) throws Exception {
        Map<String, Object> resultMap = new HashMap<>();
        List<PlugRecord> plugRecordList = plugRecordService.findByOperationId(uuid, (page - 1) * limit, limit);

        List<Map<String, Object>> recordListMap = this.convertList(plugRecordList);

        resultMap.put("page", page);
        resultMap.put("data", recordListMap);
        return resultMap;
    }

    /**
     * 获得所有数据源
     * @return
     */
    @RequestMapping(value = "/getDataSourceCombobox", method = RequestMethod.POST)
    @ResponseBody
    public Map<String, Object> getDataSourceCombobox(){
        Map<String, Object> resultMap = new HashMap<>();
        List<PlugContrast> plugContrastList = plugContrastService.findAll();
        List<Map<String, Object>> comboboxList = new ArrayList<>();
        Map<String, Object> map  = new HashMap<>();
        for (PlugContrast p : plugContrastList){
            map.put(p.getSrcDsId().toString(),p.getSrcTab());
        }
        for (String key : map.keySet()) {
            PlugDatasource pd = plugDatasourceService.findByID(Long.valueOf(key));
            Map<String, Object> map_  = new HashMap<>();
            map_.put("text", pd.getDsName());
            map_.put("value", pd.getId());
            comboboxList.add(map_);
        }
        resultMap.put("data", comboboxList);
        return resultMap;
    }

    /**
     * 获得目标数据源
     * @return
     */
    @RequestMapping(value = "/getTgtDataSourceCombobox/{id}", method = RequestMethod.POST)
    @ResponseBody
    public Map<String, Object> getTgtDataSourceCombobox(Long id){
        Map<String, Object> resultMap = new HashMap<>();
        List<PlugContrast> plugContrastList = plugContrastService.findAllTable(id);
        List<Map<String, Object>> comboboxList = new ArrayList<>();//目标数据集
        List<Map<String, Object>> comboboxTableList = new ArrayList<>();//源数据表名数据集
        Map<String, Object> map  = new HashMap<>();
        for (PlugContrast p : plugContrastList){
            map.put(p.getTgtDsId().toString(),p.getTgtTab());
            Map<String, Object> tableMap  = new HashMap<>();
            tableMap.put("text", p.getSrcTab());
            tableMap.put("value", p.getSrcTab());
            comboboxTableList.add(tableMap);
        }
        for (String key : map.keySet()) {
            PlugDatasource pd = plugDatasourceService.findByID(Long.valueOf(key));
            Map<String, Object> dsMap = new HashMap<>();
            dsMap.put("text", pd.getDsName());
            dsMap.put("value", pd.getId());
            comboboxList.add(dsMap);
        }
        resultMap.put("tableData", comboboxTableList);
        resultMap.put("tgtData", comboboxList);
        return resultMap;
    }

    /**
     * 获取目标表名
     * @param srcDsId 源数据源ID
     * @param srcDsTable 源数据源表名
     * @param tgtDsId 目标数据源ID
     * @return
     */
    @RequestMapping(value = "/getTgtSourceTable", method = RequestMethod.POST)
    @ResponseBody
    public ResponseEntity<Object> getTgtSourceTable(@Param("srcDsId")Long srcDsId,@Param("srcDsTable")String srcDsTable,@Param("tgtDsId")Long tgtDsId){
        try {
            Map<String, Object> resultMap = new HashMap<>();
            PlugContrast p= plugContrastService.findTgtTable(srcDsId,  srcDsTable ,tgtDsId);//查询备份记录
            List<Map<String, Object>> sourceTableList = new ArrayList<>();
            List<Map<String, Object>> columnListMap = new ArrayList<>();
            List<Map<String, Object>> tableStrutListMap = new ArrayList<>();
            List<String> columnList = plugRecordService.findTableColumn(plugDatasourceService.findByID(tgtDsId), p.getTgtTab());//查询表所有列
            Map<String, Object> tableStrutMap = null;
            MemoryCache mc = MemoryCache.getInstance();
            if(mc.get(tgtDsId + "_" + p.getTgtTab()) != null && !mc.get(tgtDsId + "_" + p.getTgtTab()).toString().equals("")){
                JSONObject jo = JSONObject.fromObject(mc.get(tgtDsId + "_" + p.getTgtTab()));
                tableStrutMap = JSONObject.fromObject(jo);
            } else {
                tableStrutMap = plugRecordService.findTableStrut(plugDatasourceService.findByID(tgtDsId), p.getTgtTab());//查询表时间数据结构
                mc.set(tgtDsId + "_" + p.getTgtTab(), JSONObject.fromObject(tableStrutMap), 2592000);
            }
            Map<String, Object> map  = new HashMap<>();
            map.put("text", p.getTgtTab());
            map.put("value", p.getTgtDsId());
            sourceTableList.add(map);
            Map<String, Object> columnMap = new HashMap<>();
            columnMap.put("text", "全部");
            columnMap.put("value", "全部");
            columnListMap.add(columnMap);
            for (int i = 0; i < columnList.size(); i++) {
                columnMap = new HashMap<>();
                columnMap.put("text", columnList.get(i));
                columnMap.put("value", columnList.get(i));
                columnListMap.add(columnMap);
            }
            for (String key : tableStrutMap.keySet()) {
                map = new HashMap<>();
                map.put("text", key);
                map.put("value", key);
                tableStrutListMap.add(map);
            }
            resultMap.put("data", sourceTableList);//目标数据源
            resultMap.put("tableStrutListMap", tableStrutListMap);//目标数据表结构字段
            resultMap.put("columnData", columnListMap);//表所有列数据

            JsonResult jsonResult = new JsonResult();
            if(sourceTableList == null)
                jsonResult.setMessage("备份数据源没有任何数据");
            if(tableStrutListMap == null)
                jsonResult.setMessage("备份数据表字段没有任何数据");
            if(columnListMap == null)
                jsonResult.setMessage("备份数据表字段没有任何数据");
            jsonResult.putData("data", sourceTableList);//目标数据源
            jsonResult.putData("tableStrutListMap", tableStrutListMap);//目标数据表结构字段
            jsonResult.putData("columnData", columnListMap);//表所有列数据
            return new ResponseEntity<Object>(jsonResult, HttpStatus.OK);
        } catch (Exception e){
            return new ResponseEntity<Object>(new ExceptionResult(e), HttpStatus.OK);
        }
    }

    /**
     * 将操作记录转为List<Map<String, Object>>
     * @param list
     * @return
     */
    private List<Map<String, Object>> convertList(List<PlugRecord> list){
        List<Map<String, Object>> resultList = new ArrayList<>();
        for (PlugRecord p : list) {
            Map<String, Object> map = new HashMap<>();
            String[] srcData = p.getSrcDesc().split(",&,");
            String[] tgtData = p.getTgtDesc().split(",&,");
            String[] srcColumn = p.getSrcColumn().split(",&,");
            String[] tgtColumn = p.getTgtColumn().split(",&,");
            for (int i = 0; i < tgtColumn.length; i++) {
                map.put(srcColumn[i], srcData[i]);
                map.put("tgt_"+ tgtColumn[i], tgtData[i]);
            }
            map.put("split_column", " ");
            resultList.add(map);
        }
        return resultList;
    }
}
